package com.code.utils;

import lombok.NoArgsConstructor;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;

/**
 * 时间工具类
 *
 * @author xiaoyaowang
 */
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
public class TimeUtil {

    /**
     * 年月日格式常量
     */
    public static final String Y_M_D = "yyyy-MM-dd";

    /**
     * 年月日，时分秒格式常量
     */
    public static final String Y_M_D_H_M_S = "yyyy-MM-dd HH:mm:ss";

    /**
     * 年月日，时分秒毫秒格式常量
     */
    public static final String Y_M_D_H_M_S_S = "yyyy-MM-dd HH:mm:ss:SSS";

    /**
     * 获取当前日期时间，并格式化为yyyy-MM-dd
     *
     * @return 格式为yyyy-MM-dd HH:mm:ss的当前日期时间
     */
    public static String nowDateWithYmd() {
        return DateTimeFormatter.ofPattern(Y_M_D).format(LocalDate.now());
    }

    /**
     * 取年月日的字符串格式的日期
     *
     * @param dateTime 日期
     * @return 年月日的字符串格式的日期
     */
    public static String nowDateWithYmd(Date dateTime) {
        LocalDateTime ldt = LocalDateTime.ofInstant(dateTime.toInstant(), ZoneId.systemDefault());
        return DateTimeFormatter.ofPattern(Y_M_D).format(ldt);
    }

    /**
     * 获取当前日期，并格式化为yyyy-MM-dd HH:mm:ss
     *
     * @return 格式为yyyy-MM-dd HH:mm:ss的当前日期时间
     */
    public static String nowDateTimeWithYmdHms() {
        return DateTimeFormatter.ofPattern(Y_M_D_H_M_S).format(LocalDateTime.now());
    }

    /**
     * 取年月日时分秒的字符串格式的日期
     *
     * @param dateTime 日期
     * @return 年月日时分秒的字符串格式的日期
     */
    public static String nowDateTimeWithYmdHms(Date dateTime) {
        LocalDateTime ldt = LocalDateTime.ofInstant(dateTime.toInstant(), ZoneId.systemDefault());
        return DateTimeFormatter.ofPattern(Y_M_D_H_M_S).format(ldt);
    }

    /**
     * 获取当前日期时间，并格式化为yyyy-MM-dd HH:mm:ss:SSS
     *
     * @return 格式为yyyy-MM-dd HH:mm:ss:SSS的当前日期时间
     */
    public static String nowDateTimeWithYmdHmsS() {
        return DateTimeFormatter.ofPattern(Y_M_D_H_M_S_S).format(LocalDateTime.now());
    }

    /**
     * 将LocalDateTime转换为Date
     *
     * @return LocalDateTime转换为Date的结果
     */
    public static Date localDateTimeTransferDate() {
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.now();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }

    /**
     * 获取格式化的date日期
     *
     * @param dateStr 日期字符串
     * @param format  相应的日期格式
     * @return 格式化的date日期
     */
    public static Date formatToDate(String dateStr, String format) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format);
        LocalDateTime localDateTime = LocalDateTime.parse(dateStr, dtf);
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }

    /**
     * 比较两个日期的相差毫秒数,如果开始日期比结束日期早，则返回正数，否则返回负数。
     *
     * @param start 开始日期
     * @param end   结束日期
     * @return 两个日期的相差毫秒数的比较结果
     */
    public static long compareDate(Date start, Date end) {
        long temp = 0;
        Calendar starts = Calendar.getInstance();
        Calendar ends = Calendar.getInstance();
        starts.setTime(start);
        ends.setTime(end);
        temp = ends.getTime().getTime() - starts.getTime().getTime();
        return temp;
    }

    /**
     * 比较两个日期的相差天数,如果开始日期比结束日期早，则返回正数，否则返回负数。
     *
     * @param start 开始日期
     * @param end   结束日期
     * @return 比较两个日期的相差天数的结果
     */
    public static long compareDay(Date start, Date end) {
        if (null == start || null == end) {
            return 0;
        }

        long day = compareDate(start, end);
        return day / 1000 / 60 / 60 / 24;
    }

    /**
     * 给一个日期加上N天或减去N天得到一个新的日期
     *
     * @param startDate 需要增加的日期时间
     * @param addNos    添加的天数，可以是正数也可以是负数
     * @return 操作后的日期
     */
    public static Date addDay(Date startDate, int addNos) {
        if (null == startDate) {
            startDate = new Date();
        }

        Calendar cc = Calendar.getInstance();
        cc.setTime(startDate);
        cc.add(Calendar.DATE, addNos);
        return cc.getTime();
    }

    /**
     * 日期相隔天数
     *
     * @param startDateInclusive 开始时间
     * @param endDateExclusive   结束时间
     * @return 日期相隔天数
     */
    public static long periodDays(LocalDate startDateInclusive, LocalDate endDateExclusive) {
        return endDateExclusive.toEpochDay() - startDateInclusive.toEpochDay();
    }

    /**
     * Date 转 localDate
     */
    public static LocalDate date2LocalDate(Date date) {
        Instant instant = date.toInstant();
        ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
        LocalDate localDate = zdt.toLocalDate();
        return localDate;
    }

    /**
     * 获取当天时间的前一天日期
     *
     * @param timeFormat 日期格式
     * @return 前一天日期
     */
    public static String getYesterdayByFormat(String timeFormat) {
        return LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ofPattern(timeFormat));
    }

    /**
     * date类型转为字符串
     *
     * @param date      日期类型
     * @param formatter 日期格式
     * @return 日期字符串
     */
    public static String getLocalDateStr(Date date, String formatter) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatter);
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
        String dateStr = dateTimeFormatter.format(localDateTime);
        return dateStr;
    }

}
